package indi.mozping.aqs.lockwithaqs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @author by mozping
 * @Classname MyLock
 * @Description TODO
 * @Date 2019/4/29 17:04
 */
public class MyLock implements Lock {

    /**
     * 这是内部类，内部类继承ASQ，重写ASQ中获取同步状态的几个方法(因为是实现排它锁，重写阻塞模式的方法即可)
     */
    private static class Sync extends AbstractQueuedSynchronizer {

        /**
         * state 表示获取到锁 state=1 获取到了锁，state=0，表示这个锁当前没有线程拿到
         */
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        /**
         * 尝试获取锁，将状态从0修改为1，修改成功则将自身线程设置为当前拥有锁的线程
         */
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /**
         * 释放锁，将状态修改为0，因为只有一个线程持有锁，因此不需要CAS，是线程安全的
         */
        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                throw new UnsupportedOperationException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        Condition newCondition() {
            return sync.newCondition();
        }
    }

    private static final Sync sync = new Sync();

    /**
     * 下面的实现Lock接口需要重写的方法，基本是就是调用内部内Sync的方法
     */
    @Override
    public void lock() {
        //加锁
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        //加锁,可响应中断
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        //尝试加锁
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        //加锁，可超时
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        //解锁
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        //获取Condition对象
        return sync.newCondition();
    }
}
